#pragma once
#include <cmath>
#include <iostream>

namespace TooCould {
    typedef long double Ld;
    typedef double Dbl;

    template<typename Type>
    class Numer {
    public:
        Numer() :_value(0) {}
        Numer(Type value) :_value(value) {}
        Numer(const Numer& num) :_value(num._value) {}

        const Numer& operator=(const Numer& right_operand);
        const Numer operator-() const;

        static void SetPrecision(Type precision);
        const Type Value() const { return _value; }

        bool operator==(const Numer& right_operand) const;
        bool operator!=(const Numer& right_operand) const;
        bool operator>(const Numer& right_operand) const;
        bool operator>=(const Numer& right_operand) const;
        bool operator<(const Numer& right_operand) const;
        bool operator<=(const Numer& right_operand) const;

        const Numer operator+(const Numer& right_operand) const;
        const Numer operator-(const Numer& right_operand) const;
        const Numer operator*(const Numer& right_operand) const;
        const Numer operator/(const Numer& right_operand) const;

        const Numer operator+(const Type& right_operand) const;
        const Numer operator-(const Type& right_operand) const;
        const Numer operator*(const Type& right_operand) const;
        const Numer operator/(const Type& right_operand) const;

        void operator+=(const Numer& right_operand);
        void operator-=(const Numer& right_operand);
        void operator*=(const Numer& right_operand);
        void operator/=(const Numer& right_operand);

        Numer operator^(int pow) const;
        Numer operator^(double pow) const;
        Numer operator^(const Numer& pow) const;

        friend std::ostream& operator<<(std::ostream& out, const Numer& m) {
            std::cout << m._value;
            return out;
        }
        friend std::istream& operator>>(std::istream& in, Numer& m) {
            std::cin >> m._value;
            return in;
        }

    private:
        Type _value;
        static Type _precision;
    };

    typedef Numer<Dbl> Double;
    typedef Numer<Ld> LDBL;

    Dbl Double::_precision = 0;
    Ld LDBL::_precision = 0;

    template<typename Type>
    inline void Numer<Type>::SetPrecision(Type precision) {
        Numer::_precision = precision;
    }
    template<typename Type>
    inline const Numer<Type>& Numer<Type>::operator=(const Numer& right_operand) {
        _value = right_operand;
        return *this;
    }
    template<typename Type>
    inline const Numer<Type> Numer<Type>::operator-() const {
        Numer<Type> ret(-_value);
        return ret;
    }
    template<typename Type>
    inline bool Numer<Type>::operator==(const Numer& right_operand) const {
        return std::abs(_value - right_operand._value) < _precision;
    }
    template<typename Type>
    inline bool Numer<Type>::operator!=(const Numer& right_operand) const {
        return !(*this == right_operand);
    }
    template<typename Type>
    inline bool Numer<Type>::operator>=(const Numer& right_operand) const {
        return _value > right_operand._value || (*this == right_operand);
    }
    template<typename Type>
    inline bool Numer<Type>::operator<=(const Numer& right_operand) const {
        return _value < right_operand._value || (*this == right_operand);
    }
    template<typename Type>
    inline bool Numer<Type>::operator>(const Numer& right_operand) const {
        return !(*this <= right_operand);
    }
    template<typename Type>
    inline bool Numer<Type>::operator<(const Numer& right_operand) const {
        return !(*this >= right_operand);
    }
    template<typename Type>
    inline const Numer<Type> Numer<Type>::operator+(const Numer& right_operand) const {
        return Numer<Type>(_value + right_operand._value);
    }
    template<typename Type>
    inline const Numer<Type> Numer<Type>::operator-(const Numer& right_operand) const {
        return Numer<Type>(_value - right_operand._value);
    }
    template<typename Type>
    inline const Numer<Type> Numer<Type>::operator*(const Numer& right_operand) const {
        return Numer<Type>(_value * right_operand._value);
    }
    template<typename Type>
    inline const Numer<Type> Numer<Type>::operator/(const Numer& right_operand) const {
        return Numer<Type>(_value / right_operand._value);
    }
    template<typename Type>
    inline const Numer<Type> Numer<Type>::operator+(const Type& right_operand) const {
        return Numer<Type>(_value + right_operand);
    }
    template<typename Type>
    inline const Numer<Type> Numer<Type>::operator-(const Type& right_operand) const {
        return Numer<Type>(_value - right_operand);
    }
    template<typename Type>
    inline const Numer<Type> Numer<Type>::operator*(const Type& right_operand) const {
        return Numer<Type>(_value * right_operand);
    }
    template<typename Type>
    inline const Numer<Type> Numer<Type>::operator/(const Type& right_operand) const {
        return Numer<Type>(_value / right_operand);
    }
    template<typename Type>
    inline void Numer<Type>::operator+=(const Numer& right_operand) {
        _value += right_operand._value;
    }
    template<typename Type>
    inline void Numer<Type>::operator-=(const Numer& right_operand) {
        _value -= right_operand._value;
    }
    template<typename Type>
    inline void Numer<Type>::operator*=(const Numer& right_operand) {
        _value *= right_operand._value;
    }
    template<typename Type>
    inline void Numer<Type>::operator/=(const Numer& right_operand) {
        _value /= right_operand._value;
    }
    template<typename Type>
    Numer<Type> Numer<Type>::operator^(int pow) const {
        if (pow >= 0) {
            Type ret = 1;
            for (int i = 0; i < pow; ++i)
                ret *= _value;
            return Numer<Type>(ret);
        }
        else {
            return Numer<Type>(1) / (*this ^ (-pow));
        }
    }
    template<typename Type>
    inline Numer<Type> Numer<Type>::operator^(double pow) const {
        return Numer<Type>(std::pow(_value, pow));
    }
    template<typename Type>
    inline Numer<Type> Numer<Type>::operator^(const Numer& pow) const {
        return *this ^ pow._value;
    }
}